<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>19 实际示例 - 简单 Auto Complete 实例 · ShaofeiZi Blog · 做个日常记录</title>
    <meta name="description" content="訾绍飞的博客。万物皆有裂缝处，那是光射进来的地方。">
    <link rel="shortcut icon" href="/BLOG/favicon.ico">
  <link rel="manifest" href="/BLOG/manifest.json">
  <meta name="theme-color" content="#3F51B5">
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-status-bar-style" content="black">
  <link rel="apple-touch-icon" href="/BLOG/icons/192.png">
  <link rel="mask-icon" href="/BLOG/icons/safari-pinned-tab.svg" color="#3eaf7c">
  <meta name="msapplication-TileImage" content="/icons/192.png">
  <meta name="msapplication-TileColor" content="#3F51B5">
    
    <link rel="preload" href="/BLOG/assets/css/42.styles.90045bd1.css" as="style"><link rel="preload" href="/BLOG/assets/js/app.1a725be8.js" as="script"><link rel="preload" href="/BLOG/assets/js/15.ca0178b2.js" as="script"><link rel="prefetch" href="/BLOG/assets/js/7.88ba0bb7.js"><link rel="prefetch" href="/BLOG/assets/js/0.d3e592bd.js"><link rel="prefetch" href="/BLOG/assets/js/1.39b9c99c.js"><link rel="prefetch" href="/BLOG/assets/js/2.68dc10c9.js"><link rel="prefetch" href="/BLOG/assets/js/3.dfebdd5e.js"><link rel="prefetch" href="/BLOG/assets/js/4.ea97a821.js"><link rel="prefetch" href="/BLOG/assets/js/5.d8c2ecbf.js"><link rel="prefetch" href="/BLOG/assets/js/6.e51cd79c.js"><link rel="prefetch" href="/BLOG/assets/js/8.d9eebc06.js"><link rel="prefetch" href="/BLOG/assets/js/9.1a541d13.js"><link rel="prefetch" href="/BLOG/assets/js/10.4ec9ca67.js"><link rel="prefetch" href="/BLOG/assets/js/11.02558377.js"><link rel="prefetch" href="/BLOG/assets/js/12.d0e2086f.js"><link rel="prefetch" href="/BLOG/assets/js/13.5af02ddd.js"><link rel="prefetch" href="/BLOG/assets/js/14.5d9fcbf2.js"><link rel="prefetch" href="/BLOG/assets/js/16.cd99d056.js"><link rel="prefetch" href="/BLOG/assets/js/17.56f11c1d.js"><link rel="prefetch" href="/BLOG/assets/js/18.21837cc7.js"><link rel="prefetch" href="/BLOG/assets/js/19.73335fea.js"><link rel="prefetch" href="/BLOG/assets/js/20.1632ab79.js"><link rel="prefetch" href="/BLOG/assets/js/21.43175244.js"><link rel="prefetch" href="/BLOG/assets/js/22.5b7c0cca.js"><link rel="prefetch" href="/BLOG/assets/js/23.e624ba97.js"><link rel="prefetch" href="/BLOG/assets/js/24.ac5f7b41.js"><link rel="prefetch" href="/BLOG/assets/js/25.6934a11d.js"><link rel="prefetch" href="/BLOG/assets/js/26.407b2583.js"><link rel="prefetch" href="/BLOG/assets/js/27.7449d673.js"><link rel="prefetch" href="/BLOG/assets/js/28.52e25437.js"><link rel="prefetch" href="/BLOG/assets/js/29.fba21f3a.js"><link rel="prefetch" href="/BLOG/assets/js/30.2cd6d3e2.js"><link rel="prefetch" href="/BLOG/assets/js/31.0b0a749f.js"><link rel="prefetch" href="/BLOG/assets/js/32.92134487.js"><link rel="prefetch" href="/BLOG/assets/js/33.ad2b89cc.js"><link rel="prefetch" href="/BLOG/assets/js/34.9b22334e.js"><link rel="prefetch" href="/BLOG/assets/js/35.825f3d75.js"><link rel="prefetch" href="/BLOG/assets/js/36.cc3da84c.js"><link rel="prefetch" href="/BLOG/assets/js/37.8f339f62.js"><link rel="prefetch" href="/BLOG/assets/js/38.5674618f.js"><link rel="prefetch" href="/BLOG/assets/js/39.180f0d85.js"><link rel="prefetch" href="/BLOG/assets/js/40.275f26e3.js"><link rel="prefetch" href="/BLOG/assets/js/41.ce0f5927.js">
    <link rel="stylesheet" href="/BLOG/assets/css/42.styles.90045bd1.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div data-app="true" id="app" class="application theme--light"><div class="application--wrap"><div class="v-progress-linear blog-progress" style="height:3px;display:none;"><div class="v-progress-linear__background accent" style="height:3px;opacity:0.4;width:100%;"></div><div class="v-progress-linear__bar"><!----><div class="v-progress-linear__bar__determinate accent" style="width:0%;"></div></div></div><aside class="v-navigation-drawer v-navigation-drawer--close v-navigation-drawer--fixed v-navigation-drawer--is-mobile" style="height:100%;margin-top:0px;max-height:calc(100% - 0px);transform:translateX(-240px);width:240px;"><div><div class="aside-brand-wrap"><div class="aside-brand"><a href="/BLOG/" class="aside-avatar elevation-2 router-link-active"><img src="/BLOG/face.png" alt="avatar"></a><hgroup class="mt-3 variant-hide"><div class="subheading white--text">訾绍飞</div><a href="mailto:zishaofei221@gmail.com" title="zishaofei221@gmail.com" class="aside-mail primary--text text--lighten-5">zishaofei221@gmail.com</a></hgroup></div></div><hr class="v-divider theme--dark"><div class="v-list nav-list"><div class="secondary--text"><a href="/BLOG/" class="v-list__tile v-list__tile--link"><div class="v-list__tile__avatar"><div class="v-avatar" style="height:40px;width:40px;"><i class="fa fa-home"></i></div></div><div class="v-list__tile__content">首页</div></a></div><div class="secondary--text"><a href="/BLOG/tags" class="v-list__tile v-list__tile--link"><div class="v-list__tile__avatar"><div class="v-avatar" style="height:40px;width:40px;"><i class="fa fa-tag"></i></div></div><div class="v-list__tile__content">标签</div></a></div><div class="secondary--text"><a href="https://github.com/ShaofeiZi" target="_blank" class="v-list__tile v-list__tile--link"><div class="v-list__tile__avatar"><div class="v-avatar" style="height:40px;width:40px;"><i class="fab fa-github"></i></div></div><div class="v-list__tile__content">Github</div></a></div><div class="secondary--text"><a href="/BLOG/about" class="v-list__tile v-list__tile--link"><div class="v-list__tile__avatar"><div class="v-avatar" style="height:40px;width:40px;"><i class="fa fa-user-secret"></i></div></div><div class="v-list__tile__content">About</div></a></div></div></div><div class="v-navigation-drawer__border"></div></aside><nav class="blog-toolbar v-toolbar v-toolbar--fixed theme--dark primary" style="margin-top:0px;padding-right:0px;padding-left:0px;transform:translateY(0px);"><div class="v-toolbar__content" style="height:56px;"><button type="button" class="v-btn v-btn--icon"><div class="v-btn__content"><i class="fa fa-bars"></i></div></button><div class="v-toolbar__title">19 实际示例 - 简单 Auto Complete 实例</div><div class="spacer"></div><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""><!----></div><div class="v-menu" style="display:none;"><div class="v-menu__activator"><button type="button" class="v-btn v-btn--icon"><div class="v-btn__content"><i class="fa fa-share-alt"></i></div></button></div><div class="v-menu__content" style="max-height:auto;min-width:0px;max-width:auto;top:12px;left:0px;transform-origin:top right;z-index:0;display:none;"><div class="v-list"><div class="secondary--text"><a class="v-list__tile v-list__tile--link"><div class="v-list__tile__avatar"><div class="v-avatar" style="height:40px;width:40px;"><i class="fa fa-lg fa-copy"></i></div></div><div class="v-list__tile__title">复制链接</div></a></div></div><input type="text" tabindex="-1" aria-hidden="true" value="" class="fake-hide"></div></div></div></nav><main class="v-content" style="padding-top:56px;padding-right:0px;padding-bottom:0px;padding-left:0px;"><div class="v-content__wrap"><div class="container blog-container grid-list-xl align-center"><div class="layout row wrap"><div class="flex mb-3 xs12"><article class="v-card elevation-16 post-card" style="height:undefined;"><div class="v-card__title"><div class="flex xs12"><h2 class="display-1 mb-3">19 实际示例 - 简单 Auto Complete 实例</h2><div class="post-meta"><time datetime="2018-04-29T12:16:11.000Z" class="secondary--text post-time">2018年04月29日</time></div></div></div><div class="v-card__text pt-0 pb-0"><div class="flex xs12"><div class="content custom"><h1 id="_30-天精通-rxjs-19-：-实际示例-简单-auto-complete-实例"><a href="#_30-天精通-rxjs-19-：-实际示例-简单-auto-complete-实例" aria-hidden="true" class="header-anchor">#</a> 30 天精通 RxJS(19)： 实际示例 - 简单 Auto Complete 实例</h1><p>今天我们要做一个 RxJS 的经典示例 - 自动完成 (Auto Complete)，自动完成在开发上的应用非常广泛，几乎随处可见这样的功能，只要是跟表单、搜寻相关的都会看到。</p><p>虽然是个很常见的功能，但多数的工程师都只是直接套插件来完成，很少有人会自己从头到尾把完整的逻辑写一次。如果有自己写过这个功能的工程师，应该就会知道这个功能在实现的过程中很多细节会让代码变的非常复杂，像是要如何取消上一次发送出去的 request、要如何优化请求次数... 等等，这些小细节都会让代码变的非常复杂且很难维护。</p><p>就让我们一起来用 RxJS 来实现这个功能吧！
</p><h2 id="需求分析"><a href="#需求分析" aria-hidden="true" class="header-anchor">#</a> 需求分析</h2><p>首先我们会有一个搜索框(input#search)，当我们在上面打字并停顿超过 100 毫秒就发送 HTTP Request 来取得建议选项并显示在收寻框下方(ul#suggest-list)，如果使用者在前一次发送的请求还没有回来就打了下一个字，此时前一个发送的请求就要舍弃掉，当建议选项显示之后可以用滑鼠点击取建议选项代搜索框的文字。</p><p><img src="https://res.cloudinary.com/dohtkyi84/image/upload/v1483543558/30days/autocomplete.png" alt></p><p>上面的叙述可以拆分成以下几个步骤</p><ul><li>准备 input#search 以及 ul#suggest-list 的 HTML 与 CSS</li><li>在 input#search 输入文字时，等待 100 毫秒再无输入，就发送 HTTP Request</li><li>当 Response 还没回来时，使用者又输入了下一个文字就舍弃前一次的并再发送一次新的 Request</li><li>接受到 Response 之后显示建议选项</li><li>滑鼠点击后取代 input#search 的文字</li></ul><p>基本的 HTML 跟 CSS 笔者已经帮大家完成，大家可以直接到下面的连结接着实现：</p><ul><li><a href="https://jsbin.com/yaxupi/3/edit?js,output" target="_blank" rel="noopener noreferrer">JSBin</a></li></ul><p>先让我们看一下 HTML，首先在 HTML 里有一个 input(#search)，这个 input(#search) 就是要用来输入的栏位，它下方有一个 ul(#suggest-list)，则是放建议选项的地方</p><p>CSS 的部分可以不用看，JS 的部分已经写好了要发送 API 的 url 跟方法<code>getSuggestList</code>，接着就开始实现自动完成的效果吧！</p><h3 id="第一步，取得需要的-dom-事件"><a href="#第一步，取得需要的-dom-事件" aria-hidden="true" class="header-anchor">#</a> 第一步，取得需要的 DOM 事件</h3><p>这里我们会用到 #search 以及 #suggest-list 这两个 DOM</p><pre class="language-javascript"><code><span class="token keyword">const</span> searchInput <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'search'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> suggestList <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'suggest-list'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

</code></pre><h3 id="第二步，建立所需的-observable"><a href="#第二步，建立所需的-observable" aria-hidden="true" class="header-anchor">#</a> 第二步，建立所需的 Observable</h3><p>这里我们要监听 搜索栏位的 input 事件，以及建议选项的点击事件</p><pre class="language-javascript"><code><span class="token keyword">const</span> keyword <span class="token operator">=</span> Rx<span class="token punctuation">.</span>Observable<span class="token punctuation">.</span><span class="token function">fromEvent</span><span class="token punctuation">(</span>searchInput<span class="token punctuation">,</span> <span class="token string">'input'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> selectItem <span class="token operator">=</span> Rx<span class="token punctuation">.</span>Observable<span class="token punctuation">.</span><span class="token function">fromEvent</span><span class="token punctuation">(</span>suggestList<span class="token punctuation">,</span> <span class="token string">'click'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

</code></pre><h3 id="第三步，撰写代码逻辑"><a href="#第三步，撰写代码逻辑" aria-hidden="true" class="header-anchor">#</a> 第三步，撰写代码逻辑</h3><p>每当使用者输入文字就要发送 HTTP request，并且有新的值被输入后就舍弃前一次发送的，所以这里用 switchMap</p><pre class="language-javascript"><code>keyword<span class="token punctuation">.</span><span class="token function">switchMap</span><span class="token punctuation">(</span>e <span class="token operator">=&gt;</span> <span class="token function">getSuggestList</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">)</span>

</code></pre><p>这里我们先试着订阅，看一下 API 会回传什么样的资料</p><pre class="language-javascript"><code>keyword
    <span class="token punctuation">.</span><span class="token function">switchMap</span><span class="token punctuation">(</span>e <span class="token operator">=&gt;</span> <span class="token function">getSuggestList</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span>console<span class="token punctuation">.</span>log<span class="token punctuation">)</span>

</code></pre><p>在 search 栏位乱打几个字</p><p><img src="https://res.cloudinary.com/dohtkyi84/image/upload/v1483545742/30days/wikires.png" alt></p><p>大家可以在 console 看到资料长相这样，他会回传一个数组带有四个元素，其中第一个元素是我们输入的值，第二个元素才是我们要的建议选项清单。</p><p>所以我们要取的是 response 数组的第二的元素，用 switchMap 的第二个参数来选取我们要的</p><pre class="language-javascript"><code>keyword
    <span class="token punctuation">.</span><span class="token function">switchMap</span><span class="token punctuation">(</span>
        e <span class="token operator">=&gt;</span> <span class="token function">getSuggestList</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token punctuation">(</span>e<span class="token punctuation">,</span> res<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> res<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span>
    <span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span>console<span class="token punctuation">.</span>log<span class="token punctuation">)</span>

</code></pre><p>这时再输入文字就可以看到确实是我们要的返回值</p><p><img src="https://res.cloudinary.com/dohtkyi84/image/upload/v1483546009/30days/wikirealres.png" alt></p><p>写一个 render 方法，把数组转成 li 并写入 suggestList</p><pre class="language-javascript"><code><span class="token keyword">const</span> <span class="token function-variable function">render</span> <span class="token operator">=</span> <span class="token punctuation">(</span>suggestArr <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    suggestList<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> suggestArr
                            <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>item <span class="token operator">=&gt;</span> <span class="token string">'&lt;li&gt;'</span><span class="token operator">+</span> item <span class="token operator">+</span><span class="token string">'&lt;/li&gt;'</span><span class="token punctuation">)</span>
                            <span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  
<span class="token punctuation">}</span>

</code></pre><p>这时我们就可用 render 方法把取得的数组传入</p><pre class="language-javascript"><code><span class="token keyword">const</span> <span class="token function-variable function">render</span> <span class="token operator">=</span> <span class="token punctuation">(</span>suggestArr <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    suggestList<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> suggestArr
                            <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>item <span class="token operator">=&gt;</span> <span class="token string">'&lt;li&gt;'</span><span class="token operator">+</span> item <span class="token operator">+</span><span class="token string">'&lt;/li&gt;'</span><span class="token punctuation">)</span>
                            <span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  
<span class="token punctuation">}</span>

keyword
  <span class="token punctuation">.</span><span class="token function">switchMap</span><span class="token punctuation">(</span>
    e <span class="token operator">=&gt;</span> <span class="token function">getSuggestList</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">(</span>e<span class="token punctuation">,</span> res<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> res<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span>
  <span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span>list <span class="token operator">=&gt;</span> <span class="token function">render</span><span class="token punctuation">(</span>list<span class="token punctuation">)</span><span class="token punctuation">)</span>

</code></pre><p>如此一来我们打字就能看到结果出现在 input 下方了</p><p><img src="https://res.cloudinary.com/dohtkyi84/image/upload/v1483543558/30days/autocomplete.png" alt></p><p>只是目前还不能点选，先让我们来做点选的功能，这里点选的功能我们需要用到 delegation event 的小技巧，利用 ul 的 click 事件，来筛选是否点到了 li，如下</p><pre class="language-javascript"><code>selectItem
  <span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>e <span class="token operator">=&gt;</span> e<span class="token punctuation">.</span>target<span class="token punctuation">.</span><span class="token function">matches</span><span class="token punctuation">(</span><span class="token string">'li'</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

</code></pre><p>上面我们利用 DOM 事件的 matches 方法(里面的字串放 css 的 selector)来过滤出有点击到 li 的事件，再用 map 转出我们要的值并写入 input。</p><pre class="language-javascript"><code>selectItem
  <span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>e <span class="token operator">=&gt;</span> e<span class="token punctuation">.</span>target<span class="token punctuation">.</span><span class="token function">matches</span><span class="token punctuation">(</span><span class="token string">'li'</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>e <span class="token operator">=&gt;</span> e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>innerText<span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span>text <span class="token operator">=&gt;</span> searchInput<span class="token punctuation">.</span>value <span class="token operator">=</span> text<span class="token punctuation">)</span>

</code></pre><p>现在我们就能点击建议清单了，但是点击后清单没有消失，这里我们要在点击后重新 redner，所以把上面的代码改一下</p><pre class="language-javascript"><code>selectItem
  <span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>e <span class="token operator">=&gt;</span> e<span class="token punctuation">.</span>target<span class="token punctuation">.</span><span class="token function">matches</span><span class="token punctuation">(</span><span class="token string">'li'</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>e <span class="token operator">=&gt;</span> e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>innerText<span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span>text <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> 
      searchInput<span class="token punctuation">.</span>value <span class="token operator">=</span> text<span class="token punctuation">;</span>
      <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>

</code></pre><p>这样一来我们就完成最基本的功能了，大家可以到<a href="https://jsbin.com/yaxupi/6/edit?js,output" target="_blank" rel="noopener noreferrer">这里</a>看初步的完成品。</p><p>还记得我们前面说每次打完字要等待 100 毫秒在发送 request 吗？ 这样能避免过多的 request 发送，可以降低 server 的负载也会有比较好的使用者体验，要做到这件事很简单只要加上 <code>debounceTime(100)</code> 就完成了</p><pre class="language-javascript"><code>keyword
  <span class="token punctuation">.</span><span class="token function">debounceTime</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">switchMap</span><span class="token punctuation">(</span>
    e <span class="token operator">=&gt;</span> <span class="token function">getSuggestList</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">(</span>e<span class="token punctuation">,</span> res<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> res<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span>
  <span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span>list <span class="token operator">=&gt;</span> <span class="token function">render</span><span class="token punctuation">(</span>list<span class="token punctuation">)</span><span class="token punctuation">)</span>

</code></pre><p>当然这个数值可以依照需求或是请 UX 针对这个细节作调整。</p><p>这样我们就完成所有功能了，大家可以到<a href="https://jsbin.com/yaxupi/7/edit?js,output" target="_blank" rel="noopener noreferrer">这里</a>查看结果。</p><h2 id="今日小结"><a href="#今日小结" aria-hidden="true" class="header-anchor">#</a> 今日小结</h2><p>我们用了不到 30 行的代码就完成了 auto complete 的基本功能，当我们能够自己从头到尾的完成这样的功能，在面对各种不同的需求，我们就能很方便的针对需求作调整，而不会受到插件的限制！比如说我们希望使用者打了 2 个字以上在发送 request，这时我们只要加上一行 filter 就可以了</p><pre class="language-javascript"><code>keyword
  <span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>e <span class="token operator">=&gt;</span> e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">.</span>length <span class="token operator">&gt;</span> <span class="token number">2</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">debounceTime</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">switchMap</span><span class="token punctuation">(</span>
    e <span class="token operator">=&gt;</span> <span class="token function">getSuggestList</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">(</span>e<span class="token punctuation">,</span> res<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> res<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span>
  <span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span>list <span class="token operator">=&gt;</span> <span class="token function">render</span><span class="token punctuation">(</span>list<span class="token punctuation">)</span><span class="token punctuation">)</span>

</code></pre><p>又或者网站的使用量很大，可能 API 在量大的时候会回传失败，主管希望可以在 API 失败的时候重新尝试 3 次，我们只要加个 <code>retry(3)</code> 就完成了</p><pre class="language-javascript"><code>keyword
  <span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>e <span class="token operator">=&gt;</span> e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">.</span>length <span class="token operator">&gt;</span> <span class="token number">2</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">debounceTime</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">switchMap</span><span class="token punctuation">(</span>
    e <span class="token operator">=&gt;</span> Rx<span class="token punctuation">.</span>Observable<span class="token punctuation">.</span><span class="token keyword">from</span><span class="token punctuation">(</span><span class="token function">getSuggestList</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">)</span>
                      <span class="token punctuation">.</span><span class="token function">retry</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">(</span>e<span class="token punctuation">,</span> res<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> res<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span>
  <span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span>list <span class="token operator">=&gt;</span> <span class="token function">render</span><span class="token punctuation">(</span>list<span class="token punctuation">)</span><span class="token punctuation">)</span>

</code></pre><p>大家会发现我们的灵活度变的非常高，又同时兼顾了代码的可读性，短短的几行代码就完成了一个复杂的需求，这就是 RxJS 的魅力啊～</p></div></div></div><div class="v-card__actions"><div class="flex xs12"><a href="/BLOG/tags/RXJS"><span tabindex="0" class="v-chip capitalize chip-tag v-chip--label v-chip--small"><span class="v-chip__content">RXJS</span></span></a></div></div></article></div><div class="flex text-xs-left xs6"><a href="/BLOG/posts/rxjs20.html" class="post-nav v-btn v-btn--flat v-btn--router"><div class="v-btn__content"><div class="grey--text"><i class="fa mr-1 fa-chevron-left"></i>Prev</div><div class="title mt-1 primary--text hidden-xs-only">20 Observable Operators - window, windowToggle, groupBy</div></div></a></div><div class="flex text-xs-right xs6"><a href="/BLOG/posts/rxjs18.html" class="post-nav v-btn v-btn--flat v-btn--router"><div class="v-btn__content"><div class="grey--text">Next
          <i class="fa ml-1 fa-chevron-right"></i></div><div class="title mt-1 primary--text hidden-xs-only">18 Observable Operators - switchMap, mergeMap, concatMap</div></div></a></div><div class="flex mt-3 xs12"><div class="v-card" style="height:undefined;"><div class="v-card__title"><span class="headline">Comment</span></div></div></div></div></div><footer class="v-footer blog-footer darken-1 mt-3 theme--dark" style="height:auto;"><div class="primary--text text--lighten-4 text-xs-center py-3 v-card v-card--flat v-card--tile primary" style="height:undefined;"><div class="v-card__text pb-0">博客内容遵循 <a rel="license noopener noreferrer" href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh" target="_blank">知识共享 署名 - 非商业性 - 相同方式共享 4.0 国际协议</a></div><div class="v-card__text pt-0 mt-1"><span>訾绍飞 © 2015 - 2018</span><span><!---->
        Power by
        <a href="https://vuepress.vuejs.org" target="_blank" rel="noopener noreferrer">VuePress</a> Theme
        <a href="https://github.com/ShaofeiZi/BLOG" target="_blank" rel="noopener noreferrer">indigo</a></span></div></div></footer></div></main><button type="button" class="v-btn v-btn--bottom v-btn--floating v-btn--fixed v-btn--right accent" style="display:none;"><div class="v-btn__content"><i class="fa fa-lg fa-chevron-up"></i></div></button></div></div></div>
    <script src="/BLOG/assets/js/15.ca0178b2.js" defer></script><script src="/BLOG/assets/js/app.1a725be8.js" defer></script>
  </body>
</html>
